package com.ww.java8.fp.stream.inaction.ch05;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class RealWar {

    public static void main(String[] args) {
        Trader raoul = new Trader("Raoul", "Cambridge");
        Trader mario = new Trader("Mario", "Milan");
        Trader alan = new Trader("Alan", "Cambridge");
        Trader brian = new Trader("Brain", "Cambridge");

        List<Transaction> transactions = Arrays.asList(
                new Transaction(brian, 2011, 300),
                new Transaction(raoul, 2012, 1000),
                new Transaction(raoul, 2011, 400),
                new Transaction(mario, 2012, 710),
                new Transaction(mario, 2012, 700),
                new Transaction(alan, 2012, 950)
        );


        List<Transaction> tr2011 = transactions.stream()
                .filter(transaction -> transaction.getYear() == 2011)
                // 按交易额进行排序
                .sorted(Comparator.comparing(Transaction::getValue))
                // 将生成的Stream中的所有元素收集到一个List中
                .collect(Collectors.toList());
        System.out.println("2011年按交易额排序：");
        tr2011.stream().forEach(System.out::println);

        System.out.println("交易员在哪些不同的城市工作过");
        List<String> cities = transactions.stream()
                .map(transaction -> transaction.getTrader().getCity())
                .distinct()
                .collect(Collectors.toList());
        cities.stream().forEach(System.out::println);

        System.out.println("查找所有来自剑桥的交易员，并按姓名排序");
        List<Trader> traders = transactions.stream()
                .map(Transaction::getTrader)
                .filter(trader -> trader.getCity().equals("Cambridge"))
                .distinct()
                .sorted(Comparator.comparing(Trader::getName))
                .collect(Collectors.toList());
        traders.stream()
                .forEach(System.out::println);

        System.out.println("返回所有交易员的姓名字符串，按字母顺序排序");
        String traderStr = transactions.stream()
                .map(transaction -> transaction.getTrader().getName())
                .distinct()
                // 对姓名按字母顺序排序
                .sorted()
                // 归约，合并字符串
                // 此解决方案效率不高（所有字符串都被反复连接，每次迭代的时候都要建立一个新的String对象）
                .reduce("", (n1, n2) -> n1 + n2);
        System.out.println(traderStr);

        // 效率更高的方法
        String tradeStr2 = transactions.stream()
                .map(transaction -> transaction.getTrader().getName())
                .distinct()
                .sorted()
                .collect(Collectors.joining());
        System.out.println(tradeStr2);

        // 有没有交易员在米兰工作
        boolean milan = transactions.stream()
                .anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan"));

        // 打印生活在剑桥的交易员的所有交易额
        transactions.stream()
                .filter(t -> "Cambridge".equals(t.getTrader().getCity()))
                // 提取这些交易的交易额
                .map(Transaction::getValue)
                .forEach(System.out::println);

        // 所有交易中，最高交易额是多少
        Optional<Integer> highestValue = transactions.stream()
                .map(Transaction::getValue)
                .reduce(Integer::max);
        System.out.println("所有交易中，最高交易额是多少" + highestValue.get());

        // 找到交易额最小的交易
        Optional<Transaction> smallestTransaction = transactions.stream()
                .reduce((t1, t2) -> t1.getValue() < t2.getValue() ? t1 : t2);
        System.out.println("方法1找到交易额最小交易" + smallestTransaction.get());

        // 流支持min和max方法，可以接受一个Comparator作为参数，指定计算最小或最大值时要比较哪个键值：
        Optional<Transaction> smallestTransaction2 = transactions.stream()
                .min(Comparator.comparing(Transaction::getValue));
        System.out.println("方法2找到交易额最小交易" + smallestTransaction2.get());

        System.out.println("========================================");

        /**
         * 你在filter之后调用boxed，从rangeClosed返回的IntStream生成一个Stream<Integer>，这是因为你的map会为流中的每个元素返回一个int数组，
         * 而IntStream中的map方法只能为流中的每个元素返回另一个int，这可不是你想要的，可以使用IntStream的mapToObj方法改写它，这个方法会返回一个对象值流
         */
        Stream<int[]> pythagoreanTriples = IntStream.rangeClosed(1, 100).boxed()
                .flatMap(a -> IntStream.rangeClosed(a, 100)
                        .filter(b -> Math.sqrt(a * a + b * b) % 1 == 0)
                        .mapToObj(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)}));

        pythagoreanTriples.limit(5)
                .forEach(t -> System.out.println(t[0] + ", " + t[1] + ", " + t[2]));

        /**
         * 做得更好
         * 先生成所有的三元数（a*a, b*b, a*a+b*b），然后再筛选符合条件的
         */
        IntStream.rangeClosed(1, 100).boxed()
                .flatMap(a -> IntStream.rangeClosed(a, 100)
                        .mapToObj(b -> new double[]{ a, b, Math.sqrt(a * a + b * b) })
                        .filter(t -> t[2] % 1 == 0));
    }
}
